Skip to content

Create shared Android CI workflow#12

Merged
gpunto merged 3 commits intodevelopfrom
and-781/unify-android-ci
Dec 23, 2025
Merged

Create shared Android CI workflow#12
gpunto merged 3 commits intodevelopfrom
and-781/unify-android-ci

Conversation

@gpunto
Copy link
Collaborator

@gpunto gpunto commented Dec 18, 2025

Summary by CodeRabbit

  • Chores
    • Added an Android CI workflow to run builds, static checks, and unit tests with an optional API-check toggle and conditional external analysis for PRs from the main repo.
    • Consolidated and renamed CI steps to centralize static checks (Spotless, Detekt) and reuse a shared Gradle setup.
    • Added automated workflow syntax validation.
    • Hardening: improved shell quoting and variable handling across SDK size and PR-quality workflows to make CI more robust.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 18, 2025

Walkthrough

Adds a reusable Android CI workflow and updates several existing GitHub Actions workflows: renames and consolidates static checks, replaces formatting check with Spotless, inlines Detekt, adds actionlint validation, and applies safer shell quoting and minor shell fixes across PR-quality and SDK size workflows.

Changes

Cohort / File(s) Summary
New reusable Android CI workflow
​.github/workflows/android-ci.yml
Adds a workflow_call reusable workflow with optional boolean input api-check (default true), exposes repository secrets (including SONAR_TOKEN) as env vars, and defines jobs: build (checkout, shared setup-gradle, ./gradlew assembleDebug --scan), static-checks (spotlessCheck, lint always(), conditional apiCheck), unit-test (checkout with fetch-depth: 0, ./gradlew testCoverage --scan --stacktrace, upload test results on failure, conditional Sonar run only when PR head repo == repo), and validate-workflows (actionlint).
Updated CI workflow
​.github/workflows/ci.yml
Renames job formatstatic-checks, replaces formatting check with Spotless, inlines Detekt as a step (with if: always()), and adds validate-workflows job running actionlint.
Shell/regex robustness fixes
​.github/workflows/pr-quality.yml
Quotes a pattern comparison ([[ "$l" == pr:* ]]) and interpolates hdr into an awk regex (^###[[:space:]]*${hdr}[[:space:]]*$) to make header matching and string comparisons safer.
Quoting and path-safety fixes (metrics/SDK)
​.github/workflows/sdk-size-checks.yml, ​.github/workflows/sdk-size-updates.yml
Wraps variable references in quotes across Gradle invocations, jq, git commands, file moves, and env exports (e.g., "$METRICS_FILE", "$BRANCH_NAME", :"metrics":"$METRICS_PROJECT":assemble) to ensure correct handling of spaces/unexpected characters without changing control flow.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Verify conditional Sonar execution and fork-detection logic in unit-test (github context PR head repo check and safe use of SONAR_TOKEN).
  • Confirm workflow_call inputs and exposed secrets are correctly declared and consumed as environment variables.
  • Check static-checks ordering and if: always() usage for Spotless, lint, and Detekt steps.
  • Validate quoting changes in SDK workflows (ensure no unintended variable expansion or command syntax changes).
  • Review pr-quality.yml regex interpolation for edge cases and shell portability.

Possibly related PRs

Suggested reviewers

  • VelikovPetar

Poem

"I hopped through YAML lanes at night,
Gradle carrots shining bright,
Spotless trails and Detekt ears,
Sonar hums while actionlint clears,
CI burrow snug — a rabbit's delight." 🥕🐇

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Create shared Android CI workflow' accurately describes the primary change: introducing a new reusable Android CI workflow (android-ci.yml) that consolidates CI logic with configurable inputs and shared Gradle setup.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch and-781/unify-android-ci

📜 Recent review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 02de4b3 and 5b1d536.

📒 Files selected for processing (5)
  • .github/workflows/android-ci.yml (1 hunks)
  • .github/workflows/ci.yml (3 hunks)
  • .github/workflows/pr-quality.yml (2 hunks)
  • .github/workflows/sdk-size-checks.yml (3 hunks)
  • .github/workflows/sdk-size-updates.yml (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/android-ci.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build and validate
🔇 Additional comments (14)
.github/workflows/ci.yml (4)

13-14: LGTM! Clear and descriptive job naming.

The rename from format to static-checks better reflects the job's expanded scope, now covering both Spotless and Detekt checks.


25-26: LGTM! Spotless check properly configured.

The step name clearly identifies the tool being used while maintaining the correct Gradle task.


28-30: Verify the if: always() condition.

Using if: always() means Detekt will run even if the workflow is cancelled. This provides comprehensive feedback but may consume unnecessary CI resources. Consider whether if: success() || failure() would be more appropriate to skip execution on cancellation while still running after Spotless failures.


47-52: Good practice for workflow validation. Version is current.

The addition of actionlint validation is excellent for catching workflow syntax issues. v2.1.0 is the latest version, so the pinned version is appropriate.

.github/workflows/pr-quality.yml (2)

43-43: LGTM! Defensive shell quoting applied.

Adding quotes around "$l" is a good defensive practice, ensuring robust handling of labels with spaces or special characters.


66-66: LGTM! Correct variable interpolation.

Changing $hdr to ${hdr} ensures proper shell variable expansion within the AWK argument. This is a correctness improvement, not just a stylistic change.

.github/workflows/sdk-size-checks.yml (3)

45-45: LGTM! Robust shell quoting applied.

Adding quotes around "$METRICS_PROJECT" in the Gradle task path ensures correct handling of project names containing spaces or special characters.


57-58: LGTM! Defensive quoting for file operations.

Quoting "$METRICS_FILE" and "$GITHUB_ENV" protects against path-related issues and follows shell scripting best practices.


77-77: LGTM! Consistent environment variable handling.

The quoting around "$GITHUB_ENV" maintains consistency with other environment variable operations in this workflow.

.github/workflows/sdk-size-updates.yml (5)

47-47: LGTM! Consistent Gradle task quoting.

Quoting "$METRICS_PROJECT" ensures the Gradle task path is correctly formed regardless of project name content, matching the pattern used in sdk-size-checks.yml.


85-85: LGTM! Safe file operation.

Quoting "$METRICS_FILE" in the mv command is essential for handling file paths that may contain spaces.


90-90: LGTM! Robust jq command.

Adding quotes around "$module" and "$METRICS_FILE" ensures the jq command handles special characters correctly.


100-101: LGTM! Critical quoting for git operations.

Quoting "$BRANCH_NAME" in git commands is particularly important since branch names can contain special characters like slashes, and this prevents potential command injection issues.


106-106: LGTM! Proper quoting in git add.

Quoting "$METRICS_FILE" while leaving the literal README.md unquoted is the correct approach.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gpunto gpunto force-pushed the and-781/unify-android-ci branch 3 times, most recently from c7e4766 to 5d517b3 Compare December 18, 2025 11:08
@gpunto gpunto marked this pull request as ready for review December 18, 2025 11:11
- name: Build and validate
run: ./gradlew build :plugin:validatePlugins

validate-workflows:
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took the chance to add a validation step for actions and workflows.

@gpunto gpunto force-pushed the and-781/unify-android-ci branch from 5d517b3 to 6c536d3 Compare December 18, 2025 11:14
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
.github/workflows/android-ci.yml (1)

36-36: Consider using a stable ref instead of @main for the setup-gradle action.

Referencing @main means any push to main could unexpectedly change behavior in consuming workflows. For stability, consider using a tagged version or commit SHA.

🔎 Example:
-     - uses: GetStream/stream-build-conventions-android/.github/actions/setup-gradle@main
+     - uses: GetStream/stream-build-conventions-android/.github/actions/setup-gradle@v1.0.0

Also applies to: 45-45, 60-60

.github/workflows/ci.yml (1)

47-52: Add explicit step names for consistency.

The checkout step in the validate-workflows job lacks an explicit name attribute, unlike other checkout steps in this workflow. For clarity, add name: Checkout and also consider adding name: Validate workflows to the actionlint step.

Additionally, pinning to a commit SHA is the most secure option, though this is optional for well-maintained third-party actions.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f63ab3d and 5d517b3.

📒 Files selected for processing (2)
  • .github/workflows/android-ci.yml (1 hunks)
  • .github/workflows/ci.yml (3 hunks)
🔇 Additional comments (3)
.github/workflows/ci.yml (1)

13-30: LGTM - Well-structured static checks job.

The consolidation of Spotless and Detekt into a single static-checks job is clean. Using if: always() on Detekt ensures both checks run and report independently, which is good for comprehensive feedback on PRs.

.github/workflows/android-ci.yml (2)

69-76: Good fork-aware Sonar handling.

The conditional logic to skip Sonar for fork PRs is a solid security practice since secrets are not available to workflows triggered from forks. The informational message on line 75-76 helps maintainers understand why Sonar was skipped.


63-68: Test results upload looks good.

The if: failure() condition ensures test results are only uploaded when tests fail, which is efficient. The glob pattern ** will capture all test reports.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
.github/workflows/android-ci.yml (2)

12-22: SONAR_TOKEN should be optional to avoid fork PR failures.

This issue was previously flagged: marking SONAR_TOKEN as required: true will cause workflow invocation failures for fork PRs that cannot supply the secret, even though the Sonar step is conditionally skipped for forks. Make it required: false and update the Sonar condition (lines 70-73) to check both the repo match and secret availability.


51-53: Boolean input compared as string.

This issue was previously flagged: inputs.api-check is defined as type: boolean but the condition compares it to the string 'true'. Use direct boolean evaluation instead.

Apply this fix:
-        if: always() && inputs.api-check == 'true'
+        if: always() && inputs.api-check
🧹 Nitpick comments (1)
.github/workflows/android-ci.yml (1)

36-36: Pin setup-gradle action to a specific version.

The setup-gradle action references @main, which can change unexpectedly and break CI. Pin to a specific tag or commit SHA for reproducibility and stability.

Example fix:
-      - uses: GetStream/stream-build-conventions-android/.github/actions/setup-gradle@main
+      - uses: GetStream/stream-build-conventions-android/.github/actions/setup-gradle@v1.0.0

Apply this pattern to all three occurrences (lines 36, 45, 60).

Also applies to: 45-45, 60-60

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5d517b3 and 6c536d3.

📒 Files selected for processing (1)
  • .github/workflows/android-ci.yml (1 hunks)
🔇 Additional comments (2)
.github/workflows/android-ci.yml (2)

62-62: Verify testCoverage task exists in consuming projects.

The workflow invokes ./gradlew testCoverage, which is a custom task that may not exist in all Android projects. Ensure that any project calling this reusable workflow defines this task, or consider using standard tasks like test with coverage configuration.

Would you like me to generate a script to check if testCoverage is defined in standard Android Gradle plugins, or would documentation suffice?


78-83: LGTM - validate-workflows job follows best practices.

The actionlint validation is properly configured with a pinned version, providing good workflow quality checks.

@gpunto gpunto force-pushed the and-781/unify-android-ci branch from 6c536d3 to 34d9817 Compare December 18, 2025 11:32
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
.github/workflows/android-ci.yml (1)

51-53: Boolean input compared as string - use direct boolean evaluation.

The inputs.api-check is defined as type: boolean, but the condition compares it to the string 'true'. Boolean inputs should be compared directly without quotes.

🔎 Apply this fix:
       - name: API check
-        if: always() && inputs.api-check == 'true'
+        if: always() && inputs.api-check
         run: ./gradlew apiCheck
🧹 Nitpick comments (2)
.github/workflows/android-ci.yml (2)

36-36: Consider pinning the setup-gradle action to a specific version.

The workflow references @main, which can introduce unexpected breaking changes. For stability and reproducibility, pin to a specific tag or commit SHA.

🔎 Example fix (apply to lines 36, 45, and 60):
-      - uses: GetStream/stream-build-conventions-android/.github/actions/setup-gradle@main
+      - uses: GetStream/stream-build-conventions-android/.github/actions/setup-gradle@v1.0.0

69-73: Add check for SONAR_TOKEN availability in Sonar step condition.

Since SONAR_TOKEN is now optional (required: false), the Sonar step should verify the token is available before attempting to use it, preventing potential failures when the token is not provided.

🔎 Apply this fix:
       - name: Sonar
-        if: github.event.pull_request.head.repo.full_name == github.repository
+        if: github.event.pull_request.head.repo.full_name == github.repository && secrets.SONAR_TOKEN != ''
         run: ./gradlew sonar
         env:
           SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6c536d3 and 34d9817.

📒 Files selected for processing (1)
  • .github/workflows/android-ci.yml (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build and validate

@gpunto gpunto requested a review from a team December 18, 2025 11:51
@gpunto gpunto force-pushed the and-781/unify-android-ci branch 2 times, most recently from b3f961c to 02de4b3 Compare December 19, 2025 12:10
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
.github/workflows/android-ci.yml (1)

71-75: Add SONAR_TOKEN availability check to prevent runtime failure.

The Sonar step checks if the PR is from a fork, but doesn't verify that SONAR_TOKEN is actually available. Since the secret is now optional (required: false at line 22), a caller might not provide it. If the token is missing when this step runs, ./gradlew sonar will likely fail.

🔎 Recommended fix

Update the condition to also check token availability:

       - name: Sonar
-        if: github.event.pull_request.head.repo.full_name == github.repository
+        if: github.event.pull_request.head.repo.full_name == github.repository && secrets.SONAR_TOKEN != ''
         run: ./gradlew sonar
         env:
           SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

Also update the skip message condition to be more accurate:

       - name: Sonar skipped if PR from fork
-        if: github.event.pull_request.head.repo.full_name != github.repository
+        if: github.event.pull_request.head.repo.full_name != github.repository || secrets.SONAR_TOKEN == ''
-        run: echo "⚠️ Sonar skipped because the PR comes from a fork."
+        run: echo "⚠️ Sonar skipped because the PR comes from a fork or SONAR_TOKEN is not available."
🧹 Nitpick comments (1)
.github/workflows/android-ci.yml (1)

36-36: Pin setup-gradle action to a stable version.

The setup-gradle action is referenced using @main, which can introduce instability if the main branch changes. This pattern appears in all jobs (lines 36, 45, 62).

Best practice is to pin to a specific version tag or commit SHA for reproducibility and stability.

🔎 Example fix for all occurrences

Replace @main with a specific version tag, e.g., @v1.0.0 (adjust based on available versions):

-      - uses: GetStream/stream-build-conventions-android/.github/actions/setup-gradle@main
+      - uses: GetStream/stream-build-conventions-android/.github/actions/setup-gradle@v1.0.0

Apply this change to lines 36, 45, and 62.

Alternatively, use a commit SHA for even more precise pinning:

-      - uses: GetStream/stream-build-conventions-android/.github/actions/setup-gradle@main
+      - uses: GetStream/stream-build-conventions-android/.github/actions/setup-gradle@abc1234
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b3f961c and 02de4b3.

📒 Files selected for processing (1)
  • .github/workflows/android-ci.yml (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run static checks
  • GitHub Check: Build and validate
🔇 Additional comments (5)
.github/workflows/android-ci.yml (5)

1-22: LGTM - Past review feedback addressed.

The workflow inputs and secrets are properly configured. The SONAR_TOKEN is now marked as optional (required: false), which resolves the previous concern about fork PRs failing when they cannot provide the secret.


24-28: LGTM - Appropriate environment variable scope.

The build cache secrets are correctly mapped at the workflow level for reuse across jobs, while SONAR_TOKEN is appropriately scoped to only the step that requires it.


40-53: LGTM - Boolean input correctly evaluated.

The static checks are well-structured. The always() conditions ensure that lint and API checks run even if earlier steps fail, and the boolean input comparison at line 52 correctly uses direct evaluation rather than string comparison (addressing previous feedback).


65-70: LGTM - Test results properly captured on failure.

Uploading test results as artifacts on failure is a good practice for debugging. The path pattern correctly captures all test reports across modules.


84-85: No action required. v2.1.0 is the latest stable version of raven-actions/actionlint.

@gpunto gpunto force-pushed the and-781/unify-android-ci branch from 02de4b3 to 5b1d536 Compare December 19, 2025 13:08
@gpunto gpunto merged commit 77f8229 into develop Dec 23, 2025
3 checks passed
@gpunto gpunto deleted the and-781/unify-android-ci branch December 23, 2025 16:03
@coderabbitai coderabbitai bot mentioned this pull request Jan 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments